<?php

namespace Giikin\TokenAuth\Middleware;

use Giikin\TokenAuth\Constant\ErrorCode;
use Giikin\TokenAuth\Constant\RedisConst;
use Giikin\TokenAuth\Exception\RunnerException;
use Giikin\TokenAuth\SSOUser;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Hyperf\Context\Context;
use Hyperf\Redis\RedisFactory;
use Hyperf\Utils\ApplicationContext;
use Hyperf\Utils\Codec\Json;
use Hyperf\HttpMessage\Stream\SwooleStream;

class TokenAuthMiddleware implements MiddlewareInterface
{
    private $allowedTokens;

    public function __construct(array $allowedTokens)
    {
        $this->allowedTokens = $allowedTokens;
    }

    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
    {
//        if (env('APP_ENV', 'dev') != 'prod') {
//            return $handler->handle($request);
//        }
        $response = Context::get(ResponseInterface::class);
        try {
            $authorization = $request->getHeader('Authorization');
            if (empty($authorization)) {
                throw new RunnerException(ErrorCode::HTTP_ERROR_401, '无效的Authorization');
            }
            $authorization = current($authorization);
            $authorization = explode(' ', $authorization);

            if (count($authorization) != 2 || ucfirst($authorization[0]) != 'Bearer') {
                throw new RunnerException(ErrorCode::HTTP_ERROR_401, 'Authorization参数错误');
                // auth error
            }
            // Bearer token
            $token = $authorization[1];
            $redis = ApplicationContext::getContainer()->get(RedisFactory::class)->get();
            $userInfo = $redis->get(sprintf(RedisConst::USER_TOKEN_CACHE, $token));
            if ($userInfo) {
                $userInfo = json_decode($userInfo, true);
            } else {
                $info = make(SSOUser::class)->getUserInfo($token);
                if (($info['code'] ?? '') !== 0) {
                    $message = $info['comment'] ?? '接口异常';
                    $message = "sso.{$info['code']}:$message";
                    throw new RunnerException(ErrorCode::HTTP_ERROR_401, $message);
                }
                $userInfo = array_intersect_key($info['data'], [
                    'id'       => '',
                    'name'     => '',
                    'account'  => '',
                    'area_id'  => '',
                    'org_code' => '',
                    'avatar'   => '',
                    'phone'    => '',
                    'roles'    => [],
                    'job'      => ''
                ]);

                $redis->set(
                    sprintf(RedisConst::USER_TOKEN_CACHE, $token),
                    json_encode($userInfo, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE),
                    86400
                );
            }
            $request = $request->withAttribute('user_info', $userInfo);
            Context::set(ServerRequestInterface::class, $request);
        } catch (\Exception $e) {
            if ($e->getCode() == ErrorCode::HTTP_ERROR_401) {
                $data = Json::encode([
                                         'code'     => ErrorCode::HTTP_ERROR_401,
                                         'location' => 'https://gsso.giikin.com/admin/login/index.html?_system=18&_url=https%3A%2F%2Fgsmp.giikin.com%2Fhome'
                                     ]);
                return $response->withHeader('Server', 'Hyperf')
                                ->withAddedHeader('content-type', 'application/json; charset=utf-8')
                                ->withStatus(200)
                                ->withBody(new SwooleStream($data));
            }
            throw $e;
        }
        return $handler->handle($request);
    }
}
